package core

import "testing"

func TestNewParser(t *testing.T) {
	// Test with empty tokens slice
	tokens := []Token{}
	parser := NewParser(tokens)

	if parser.peek != 1 {
		t.Errorf("Expected peek to be 1, got %d", parser.peek)
	}

	// Test with single EOF token
	tokens = []Token{{Type: EOF}}
	parser = NewParser(tokens)

	if parser.peek != 1 {
		t.Errorf("Expected peek to be 1, got %d", parser.peek)
	}

	if parser.currentToken.Type != EOF {
		t.Errorf("Expected currentToken to be EOF, got %s", parser.currentToken.Type)
	}

	if parser.peekToken.Type != EOF {
		t.Errorf("Expected peekToken to be EOF, got %s", parser.peekToken.Type)
	}

	// Test with multiple tokens
	tokens = []Token{
		{Type: SYMBOL, Lexeme: "test"},
		{Type: BOOLEAN, Lexeme: "#t"},
		{Type: EOF},
	}
	parser = NewParser(tokens)

	if parser.peek != 1 {
		t.Errorf("Expected peek to be 1, got %d", parser.peek)
	}

	if parser.currentToken.Type != SYMBOL {
		t.Errorf("Expected currentToken to be SYMBOL, got %s", parser.currentToken.Type)
	}

	if parser.currentToken.Lexeme != "test" {
		t.Errorf("Expected currentToken lexeme to be 'test', got %s", parser.currentToken.Lexeme)
	}

	if parser.peekToken.Type != BOOLEAN {
		t.Errorf("Expected peekToken to be BOOLEAN, got %s", parser.peekToken.Type)
	}

	if parser.peekToken.Lexeme != "#t" {
		t.Errorf("Expected peekToken lexeme to be '#t', got %s", parser.peekToken.Lexeme)
	}
}

func TestParse001(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{
			input: "#t",
			want:  "#t",
		},
		/*
			{
					input: "   	#t		",
					want:  "#t",
				},
				{
					input: "   	#f		",
					want:  "#f",
				},
				{
					input: "   	define		",
					want:  "define",
				},
				{
					input: "(not #t)",
					want:  "(not #t)",
				},
				{
					input: "(	not	 #t	)",
					want:  "(not #t)",
				},
				{
					input: "(define x (not #t))",
					want:  "(define x (not #t))",
				},
				{
					input: "(let x (not #t))",
					want:  "(let x (not #t))",
				},
				{
					input: "(let 1st-x (not #t))",
					want:  "(let 1st-x (not #t))",
				},
				{
					input: "(let 1st-x (not #t))",
					want:  "(let 1st-x (not #t))",
				},
				{
					input: "(define (f x) (not x))",
					want:  "(define (f x) (not x))",
				},
				{
					input: "(let ((x #f) (y #t)) (and x y))",
					want:  "(let ((x #f) (y #t)) (and x y))",
				},//*/
	}

	for _, tt := range tests {
		lexer := NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := NewParser(tokens)
		got, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("Parse() error = %v", err)
		}
		if got.String() != tt.want {
			t.Errorf("Parse() = %v, want %v", got, tt.want)
		}
	}

}

func TestParse002(t *testing.T) {
	tests := []struct {
		input string
		want  []string
	}{
		{
			input: "#t #t",
			want:  []string{"#t", "#t"},
		},
		{
			input: "(define a #t) a",
			want:  []string{"(define a #t)", "a"},
		},
		{
			input: "(define a (or x y)) (if a b (and d c))",
			want:  []string{"(define a (or x y))", "(if a b (and d c))"},
		},
	}

	for _, tt := range tests {
		lexer := NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := NewParser(tokens)
		got, err := parser.ParseProgram()
		if err != nil {
			t.Fatalf("Parse() error = %v", err)
		}
		for i, v := range got {
			if v.String() != tt.want[i] {
				t.Errorf("Parse() = %v, want %v", got, tt.want)
			}
		}
	}

}

func TestParseExpressionFailures(t *testing.T) {
	tests := []struct {
		input         string
		expectedError string
	}{
		{
			input:         "(",
			expectedError: "unexpected end of input, expected ')'",
		},
		{
			input:         ")",
			expectedError: "unexpected token: )",
		},
		{
			input:         "(define x",
			expectedError: "unexpected end of input, expected ')'",
		},
		{
			input:         "(define x (not #t)",
			expectedError: "unexpected end of input, expected ')'",
		},
	}

	for _, tt := range tests {
		lexer := NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := NewParser(tokens)
		_, err := parser.ParseExpression()
		if err == nil {
			t.Errorf("ParseExpression(%q) expected error but got none", tt.input)
			continue
		}

		if err.Error() != tt.expectedError {
			t.Errorf("ParseExpression(%q) error = %v, want %v", tt.input, err.Error(), tt.expectedError)
		}
	}
}

func TestParseProgramFailures(t *testing.T) {
	tests := []struct {
		input         string
		expectedError string
	}{
		{
			input:         "(",
			expectedError: "unexpected end of input, expected ')'",
		},
		{
			input:         ")",
			expectedError: "unexpected token: )",
		},
		{
			input:         "(define x",
			expectedError: "unexpected end of input, expected ')'",
		},
		{
			input:         "(define x))",
			expectedError: "unexpected token: )",
		},
		{
			input:         "(define x (not #t)",
			expectedError: "unexpected end of input, expected ')'",
		},
		{
			input:         "x (",
			expectedError: "unexpected end of input, expected ')'",
		},
		{
			input:         "x )",
			expectedError: "unexpected token: )",
		},
	}

	for _, tt := range tests {
		lexer := NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := NewParser(tokens)
		_, err := parser.ParseProgram()
		if err == nil {
			t.Errorf("ParseProgram(%q) expected error but got none", tt.input)
			continue
		}

		if err.Error() != tt.expectedError {
			t.Errorf("ParseProgram(%q) error = %v, want %v", tt.input, err.Error(), tt.expectedError)
		}
	}
}
